Micron Document
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| SparkN0de-git | SparkN0de |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


Displaying Raw • Download


RNS/Identity.py fa4d4c6716d4894aba8ebddbdeec6f8061ade577 (fa4d4c67) Text, 43.52 KB

T8b949e# Reticulum License
T8b949e#
T8b949e# Copyright (c) 2016-2025 Mark Qvist
T8b949e#
T8b949e# Permission is hereby granted, free of charge, to any person obtaining a copy
T8b949e# of this software and associated documentation files (the "Software"), to deal
T8b949e# in the Software without restriction, including without limitation the rights
T8b949e# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
T8b949e# copies of the Software, and to permit persons to whom the Software is
T8b949e# furnished to do so, subject to the following conditions:
T8b949e#
T8b949e# - The Software shall not be used in any kind of system which includes amongst
T8b949e# its functions the ability to purposefully do harm to human beings.
T8b949e#
T8b949e# - The Software shall not be used, directly or indirectly, in the creation of
T8b949e# an artificial intelligence, machine learning or language model training
T8b949e# dataset, including but not limited to any use that contributes to the
T8b949e# training or development of such a model or algorithm.
T8b949e#
T8b949e# - The above copyright notice and this permission notice shall be included in
T8b949e# all copies or substantial portions of the Software.
T8b949e#
T8b949e# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
T8b949e# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
T8b949e# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
T8b949e# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
T8b949e# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
T8b949e# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
T8b949e# SOFTWARE.

Tff7b72import T7ee787math
Tff7b72import T7ee787os
Tff7b72import T7ee787RNS
Tff7b72import T7ee787time
Tff7b72import T7ee787atexit
Tff7b72import T7ee787hashlib
Tff7b72import T7ee787threading

Tff7b72from T7ee787.T7ee787vendor Tff7b72import Te6edf3umsgpack Tff7b72as Te6edf3umsgpack

Tff7b72from T7ee787RNST7ee787.T7ee787Cryptography Tff7b72import Te6edf3X25519PrivateKeyTb4b4b4, Te6edf3X25519PublicKeyTb4b4b4, Te6edf3Ed25519PrivateKeyTb4b4b4, Te6edf3Ed25519PublicKey
Tff7b72from T7ee787RNST7ee787.T7ee787Cryptography Tff7b72import Te6edf3Token


Tff7b72class T56d364IdentityTb4b4b4:
T8b949e"""
This class is used to manage identities in Reticulum. It provides methods
for encryption, decryption, signatures and verification, and is the basis
for all encrypted communication over Reticulum networks.

:param create_keys: Specifies whether new encryption and signing keys should be generated.
"""

Te6edf3CURVE Tff7b72= Ta5d6ff"Ta5d6ffCurve25519Ta5d6ff"
T8b949e"""
The curve used for Elliptic Curve DH key exchanges
"""

Te6edf3KEYSIZE Tff7b72= T79c0ff256Tff7b72*T79c0ff2
T8b949e"""
X.25519 key size in bits. A complete key is the concatenation of a 256 bit encryption key, and a 256 bit signing key.
"""

Te6edf3RATCHETSIZE Tff7b72= T79c0ff256
T8b949e"""
X.25519 ratchet key size in bits.
"""

Te6edf3RATCHET_EXPIRY Tff7b72= T79c0ff60Tff7b72*T79c0ff60Tff7b72*T79c0ff24Tff7b72*T79c0ff30
T8b949e"""
The expiry time for received ratchets in seconds, defaults to 30 days. Reticulum will always use the most recently
announced ratchet, and remember it for up to ``RATCHET_EXPIRY`` since receiving it, after which it will be discarded.
If a newer ratchet is announced in the meantime, it will be replace the already known ratchet.
"""

T8b949e# Non-configurable constants
Te6edf3TOKEN_OVERHEAD Tff7b72= Te6edf3RNSTff7b72.Td2a8ffCryptographyTff7b72.Td2a8ffTokenTff7b72.Td2a8ffTOKEN_OVERHEAD
Te6edf3AES128_BLOCKSIZE Tff7b72= T79c0ff16 T8b949e# In bytes
Te6edf3AES256_BLOCKSIZE Tff7b72= T79c0ff16 T8b949e# In bytes
Te6edf3HASHLENGTH Tff7b72= T79c0ff256 T8b949e# In bits
Te6edf3SIGLENGTH Tff7b72= Te6edf3KEYSIZE T8b949e# In bits

Te6edf3NAME_HASH_LENGTH Tff7b72= T79c0ff80
Te6edf3TRUNCATED_HASHLENGTH Tff7b72= Te6edf3RNSTff7b72.Td2a8ffReticulumTff7b72.Td2a8ffTRUNCATED_HASHLENGTH
T8b949e"""
Constant specifying the truncated hash length (in bits) used by Reticulum
for addressable hashes and other purposes. Non-configurable.
"""

Te6edf3DERIVED_KEY_LENGTH Tff7b72= T79c0ff512Tff7b72/Tff7b72/T79c0ff8
Te6edf3DERIVED_KEY_LENGTH_LEGACY Tff7b72= T79c0ff256Tff7b72/Tff7b72/T79c0ff8

T8b949e# Storage
Te6edf3known_destinations Tff7b72= Tb4b4b4{Tb4b4b4}
Te6edf3known_ratchets Tff7b72= Tb4b4b4{Tb4b4b4}

Te6edf3ratchet_persist_lock Tff7b72= Te6edf3threadingTff7b72.Td2a8ffLockTb4b4b4(Tb4b4b4)
Te6edf3known_destinations_lock Tff7b72= Te6edf3threadingTff7b72.Td2a8ffLockTb4b4b4(Tb4b4b4)

Tf0883e@staticmethod
Tff7b72def Td2a8ffrememberTb4b4b4(Te6edf3packet_hashTb4b4b4, Te6edf3destination_hashTb4b4b4, Te6edf3public_keyTb4b4b4, Te6edf3app_data Tff7b72= Tff7b72NoneTb4b4b4)Tb4b4b4:
Tff7b72if Tffa657lenTb4b4b4(Te6edf3public_keyTb4b4b4) Tff7b72!= Te6edf3IdentityTff7b72.Td2a8ffKEYSIZETff7b72/Tff7b72/T79c0ff8Tb4b4b4:
Tff7b72raise Tf85149TypeErrorTb4b4b4(Ta5d6ff"Ta5d6ffCanTa5d6ff'Ta5d6fft remember Ta5d6ff"Tff7b72+Te6edf3RNSTff7b72.Td2a8ffprettyhexrepTb4b4b4(Te6edf3destination_hashTb4b4b4)Tff7b72+Ta5d6ff"Ta5d6ff, the public key size of Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Tffa657lenTb4b4b4(Te6edf3public_keyTb4b4b4)Tb4b4b4)Tff7b72+Ta5d6ff"Ta5d6ff is not valid.Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_ERRORTb4b4b4)
Tff7b72elseTb4b4b4:
Tff7b72with Te6edf3IdentityTff7b72.Td2a8ffknown_destinations_lockTb4b4b4:
Tff7b72if Tff7b72not Te6edf3destination_hash Tff7b72in Te6edf3IdentityTff7b72.Td2a8ffknown_destinationsTb4b4b4:
Te6edf3IdentityTff7b72.Td2a8ffknown_destinationsTb4b4b4[Te6edf3destination_hashTb4b4b4] Tff7b72= Tb4b4b4[Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3packet_hashTb4b4b4, Te6edf3public_keyTb4b4b4, Te6edf3app_dataTb4b4b4, T79c0ff0Tb4b4b4]
Tff7b72elseTb4b4b4:
Te6edf3entry Tff7b72= Te6edf3IdentityTff7b72.Td2a8ffknown_destinationsTb4b4b4[Te6edf3destination_hashTb4b4b4]
Te6edf3entryTb4b4b4[T79c0ff0Tb4b4b4] Tff7b72= Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4)
Te6edf3entryTb4b4b4[T79c0ff1Tb4b4b4] Tff7b72= Te6edf3packet_hash
Te6edf3entryTb4b4b4[T79c0ff2Tb4b4b4] Tff7b72= Te6edf3public_key
Te6edf3entryTb4b4b4[T79c0ff3Tb4b4b4] Tff7b72= Te6edf3app_data

Tf0883e@staticmethod
Tff7b72def Td2a8ffrecallTb4b4b4(Te6edf3target_hashTb4b4b4, Te6edf3from_identity_hashTff7b72=Tff7b72FalseTb4b4b4, Te6edf3_no_useTff7b72=Tff7b72FalseTb4b4b4)Tb4b4b4:
T8b949e"""
Recall identity for a destination or identity hash. By default, this function
will return the identity associated with a given *destination* hash. As an
example, if you know the ``lxmf.delivery`` destination hash of an endpoint,
this function will return the associated underlying identity. You can also
search for an identity from a known *identity hash*, by setting the
``from_identity_hash`` argument.

:param target_hash: Destination or identity hash as *bytes*.
:param from_identity_hash: Whether to search based on identity hash instead of destination hash as *bool*.
:returns: An :ref:`RNS.Identity<api-identity>` instance that can be used to create an outgoing :ref:`RNS.Destination<api-destination>`, or *None* if the destination is unknown.
"""
Tff7b72if Te6edf3from_identity_hashTb4b4b4:
Tff7b72with Te6edf3IdentityTff7b72.Td2a8ffknown_destinations_lockTb4b4b4: Te6edf3destination_hashes Tff7b72= Tffa657listTb4b4b4(Te6edf3IdentityTff7b72.Td2a8ffknown_destinationsTff7b72.Td2a8ffkeysTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72for Te6edf3destination_hash Tff7b72in Te6edf3destination_hashesTb4b4b4:
Te6edf3entry Tff7b72= Te6edf3IdentityTff7b72.Td2a8ffknown_destinationsTff7b72.Td2a8ffgetTb4b4b4(Te6edf3destination_hashTb4b4b4)
Tff7b72if Tff7b72not Te6edf3entryTb4b4b4: Tff7b72continue
Tff7b72if Te6edf3target_hash Tff7b72== Te6edf3IdentityTff7b72.Td2a8fftruncated_hashTb4b4b4(Te6edf3entryTb4b4b4[T79c0ff2Tb4b4b4]Tb4b4b4)Tb4b4b4:
Tff7b72if Tff7b72not Te6edf3_no_useTb4b4b4: Te6edf3RNSTff7b72.Td2a8ffReticulumTff7b72.Td2a8ffget_instanceTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ff_used_destination_dataTb4b4b4(Te6edf3destination_hashTb4b4b4)
Te6edf3identity Tff7b72= Te6edf3IdentityTb4b4b4(Te6edf3create_keysTff7b72=Tff7b72FalseTb4b4b4)
Te6edf3identityTff7b72.Td2a8ffload_public_keyTb4b4b4(Te6edf3entryTb4b4b4[T79c0ff2Tb4b4b4]Tb4b4b4)
Te6edf3identityTff7b72.Td2a8ffapp_data Tff7b72= Te6edf3entryTb4b4b4[T79c0ff3Tb4b4b4]
Tff7b72return Te6edf3identity

Tff7b72return Tff7b72None

Tff7b72elseTb4b4b4:
Tff7b72if Te6edf3target_hash Tff7b72in Te6edf3IdentityTff7b72.Td2a8ffknown_destinationsTb4b4b4:
Tff7b72if Tff7b72not Te6edf3_no_useTb4b4b4: Te6edf3RNSTff7b72.Td2a8ffReticulumTff7b72.Td2a8ffget_instanceTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ff_used_destination_dataTb4b4b4(Te6edf3target_hashTb4b4b4)
Te6edf3identity_data Tff7b72= Te6edf3IdentityTff7b72.Td2a8ffknown_destinationsTb4b4b4[Te6edf3target_hashTb4b4b4]
Te6edf3identity Tff7b72= Te6edf3IdentityTb4b4b4(Te6edf3create_keysTff7b72=Tff7b72FalseTb4b4b4)
Te6edf3identityTff7b72.Td2a8ffload_public_keyTb4b4b4(Te6edf3identity_dataTb4b4b4[T79c0ff2Tb4b4b4]Tb4b4b4)
Te6edf3identityTff7b72.Td2a8ffapp_data Tff7b72= Te6edf3identity_dataTb4b4b4[T79c0ff3Tb4b4b4]
Tff7b72return Te6edf3identity
Tff7b72elseTb4b4b4:
Tff7b72for Te6edf3registered_destination Tff7b72in Te6edf3RNSTff7b72.Td2a8ffTransportTff7b72.Td2a8ffdestinationsTb4b4b4:
Tff7b72if Te6edf3target_hash Tff7b72== Te6edf3registered_destinationTff7b72.Td2a8ffhashTb4b4b4:
Te6edf3identity Tff7b72= Te6edf3IdentityTb4b4b4(Te6edf3create_keysTff7b72=Tff7b72FalseTb4b4b4)
Te6edf3identityTff7b72.Td2a8ffload_public_keyTb4b4b4(Te6edf3registered_destinationTff7b72.Td2a8ffidentityTff7b72.Td2a8ffget_public_keyTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3identityTff7b72.Td2a8ffapp_data Tff7b72= Tff7b72None
Tff7b72return Te6edf3identity

Tff7b72return Tff7b72None

Tf0883e@staticmethod
Tff7b72def Td2a8ffrecall_app_dataTb4b4b4(Te6edf3destination_hashTb4b4b4, Te6edf3_no_useTff7b72=Tff7b72FalseTb4b4b4)Tb4b4b4:
T8b949e"""
Recall last heard app_data for a destination hash.

:param destination_hash: Destination hash as *bytes*.
:returns: *Bytes* containing app_data, or *None* if the destination is unknown.
"""
Tff7b72if Te6edf3destination_hash Tff7b72in Te6edf3IdentityTff7b72.Td2a8ffknown_destinationsTb4b4b4:
Tff7b72if Tff7b72not Te6edf3_no_useTb4b4b4: Te6edf3RNSTff7b72.Td2a8ffReticulumTff7b72.Td2a8ffget_instanceTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ff_used_destination_dataTb4b4b4(Te6edf3destination_hashTb4b4b4)
Te6edf3app_data Tff7b72= Te6edf3IdentityTff7b72.Td2a8ffknown_destinationsTb4b4b4[Te6edf3destination_hashTb4b4b4]Tb4b4b4[T79c0ff3Tb4b4b4]
Tff7b72return Te6edf3app_data
Tff7b72elseTb4b4b4: Tff7b72return Tff7b72None

Tf0883e@staticmethod
Tff7b72def Td2a8ffsave_known_destinationsTb4b4b4(Te6edf3backgroundTff7b72=Tff7b72FalseTb4b4b4, Te6edf3recombineTff7b72=Tff7b72FalseTb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3recombineTb4b4b4: Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffRecombining known destinations from disk cache on persist is deprecated, argument ignoredTa5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_WARNINGTb4b4b4)
Tff7b72if Te6edf3RNSTff7b72.Td2a8ffTransportTff7b72.Td2a8ffownerTff7b72.Td2a8ffis_connected_to_shared_instanceTb4b4b4: Tff7b72return
Tff7b72tryTb4b4b4:
Tff7b72if Tffa657hasattrTb4b4b4(Te6edf3IdentityTb4b4b4, Ta5d6ff"Ta5d6ffsaving_known_destinationsTa5d6ff"Tb4b4b4)Tb4b4b4:
Te6edf3wait_interval Tff7b72= T79c0ff0.2
Te6edf3wait_timeout Tff7b72= T79c0ff5
Te6edf3wait_start Tff7b72= Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4)
Tff7b72while Te6edf3IdentityTff7b72.Td2a8ffsaving_known_destinationsTb4b4b4:
Te6edf3timeTff7b72.Td2a8ffsleepTb4b4b4(Te6edf3wait_intervalTb4b4b4)
Tff7b72if Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4) Tff7b72> Te6edf3wait_startTff7b72+Te6edf3wait_timeoutTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffCould not save known destinations to storage, waiting for previous save operation timed out.Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_ERRORTb4b4b4)
Tff7b72return Tff7b72False

Te6edf3IdentityTff7b72.Td2a8ffsaving_known_destinations Tff7b72= Tff7b72True
Te6edf3save_start Tff7b72= Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4)
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffSaving Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Tffa657lenTb4b4b4(Te6edf3IdentityTff7b72.Td2a8ffknown_destinationsTb4b4b4)Tb4b4b4)Tff7b72+Ta5d6ff"Ta5d6ff known destinations to storage...Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4) Tff7b72if Te6edf3RNSTff7b72.Td2a8ffslTb4b4b4(Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4) Tff7b72else Tff7b72None

Te6edf3temp_file Tff7b72= Te6edf3RNSTff7b72.Td2a8ffReticulumTff7b72.Td2a8ffstoragepathTff7b72+Ta5d6fffTa5d6ff"Ta5d6ff/known_destinations.tmp.Tffd700{Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4)Tffd700}Ta5d6ff"
Tff7b72tryTb4b4b4:
Tff7b72with Tffa657openTb4b4b4(Te6edf3temp_fileTb4b4b4,Ta5d6ff"Ta5d6ffwbTa5d6ff"Tb4b4b4) Tff7b72as Te6edf3fileTb4b4b4: Te6edf3umsgpackTff7b72.Td2a8ffdumpTb4b4b4(Te6edf3IdentityTff7b72.Td2a8ffknown_destinationsTff7b72.Td2a8ffcopyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3fileTb4b4b4)
Te6edf3osTff7b72.Td2a8ffreplaceTb4b4b4(Te6edf3temp_fileTb4b4b4, Te6edf3RNSTff7b72.Td2a8ffReticulumTff7b72.Td2a8ffstoragepathTff7b72+Ta5d6fffTa5d6ff"Ta5d6ff/known_destinationsTa5d6ff"Tb4b4b4)

Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffError while serializing and writing known destinations: Tffd700{Te6edf3eTffd700}Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_ERRORTb4b4b4)
Tff7b72tryTb4b4b4: Te6edf3osTff7b72.Td2a8ffunlinkTb4b4b4(Te6edf3temp_fileTb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4: Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffCould not clean up temporary file Tffd700{Te6edf3temp_fileTffd700}Ta5d6ff: Tffd700{Te6edf3eTffd700}Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_WARNINGTb4b4b4)
Tff7b72raise Te6edf3e

Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffSaved known destinations to storage in Tffd700{Te6edf3RNSTff7b72.Td2a8ffprettyshorttimeTb4b4b4(Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4)Tff7b72-Te6edf3save_startTb4b4b4)Tffd700}Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4) Tff7b72if Te6edf3RNSTff7b72.Td2a8ffslTb4b4b4(Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4) Tff7b72else Tff7b72None

Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffError while saving known destinations to disk, the contained exception was: Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_ERRORTb4b4b4)
Te6edf3RNSTff7b72.Td2a8fftrace_exceptionTb4b4b4(Te6edf3eTb4b4b4)

Tff7b72finallyTb4b4b4: Te6edf3IdentityTff7b72.Td2a8ffsaving_known_destinations Tff7b72= Tff7b72False

Tf0883e@staticmethod
Tff7b72def Td2a8ffload_known_destinationsTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffisfileTb4b4b4(Te6edf3RNSTff7b72.Td2a8ffReticulumTff7b72.Td2a8ffstoragepathTff7b72+Ta5d6ff"Ta5d6ff/known_destinationsTa5d6ff"Tb4b4b4)Tb4b4b4:
Te6edf3st Tff7b72= Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4)
Tff7b72tryTb4b4b4:
Tff7b72with Tffa657openTb4b4b4(Te6edf3RNSTff7b72.Td2a8ffReticulumTff7b72.Td2a8ffstoragepathTff7b72+Ta5d6ff"Ta5d6ff/known_destinationsTa5d6ff"Tb4b4b4,Ta5d6ff"Ta5d6ffrbTa5d6ff"Tb4b4b4) Tff7b72as Te6edf3fileTb4b4b4:
Te6edf3loaded_known_destinations Tff7b72= Te6edf3umsgpackTff7b72.Td2a8ffloadTb4b4b4(Te6edf3fileTb4b4b4)

Te6edf3IdentityTff7b72.Td2a8ffknown_destinations Tff7b72= Tb4b4b4{Tb4b4b4}
Tff7b72for Te6edf3known_destination Tff7b72in Te6edf3loaded_known_destinationsTb4b4b4:
Tff7b72if Tffa657lenTb4b4b4(Te6edf3known_destinationTb4b4b4) Tff7b72== Te6edf3RNSTff7b72.Td2a8ffReticulumTff7b72.Td2a8ffTRUNCATED_HASHLENGTHTff7b72/Tff7b72/T79c0ff8Tb4b4b4:
Tff7b72if Tffa657lenTb4b4b4(Te6edf3loaded_known_destinationsTb4b4b4[Te6edf3known_destinationTb4b4b4]Tb4b4b4) Tff7b72< T79c0ff5Tb4b4b4:
Te6edf3e Tff7b72= Te6edf3loaded_known_destinationsTb4b4b4[Te6edf3known_destinationTb4b4b4]
Te6edf3loaded_known_destinationsTb4b4b4[Te6edf3known_destinationTb4b4b4] Tff7b72= Tb4b4b4[Te6edf3eTb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4, Te6edf3eTb4b4b4[T79c0ff1Tb4b4b4]Tb4b4b4, Te6edf3eTb4b4b4[T79c0ff2Tb4b4b4]Tb4b4b4, Te6edf3eTb4b4b4[T79c0ff3Tb4b4b4]Tb4b4b4, T79c0ff0Tb4b4b4]

Tff7b72with Te6edf3IdentityTff7b72.Td2a8ffknown_destinations_lockTb4b4b4:
Te6edf3IdentityTff7b72.Td2a8ffknown_destinationsTb4b4b4[Te6edf3known_destinationTb4b4b4] Tff7b72= Te6edf3loaded_known_destinationsTb4b4b4[Te6edf3known_destinationTb4b4b4]

Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffLoaded Tffd700{Tffa657lenTb4b4b4(Te6edf3IdentityTff7b72.Td2a8ffknown_destinationsTb4b4b4)Tffd700}Ta5d6ff known destination from storage in Tffd700{Te6edf3RNSTff7b72.Td2a8ffprettyshorttimeTb4b4b4(Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4)Tff7b72-Te6edf3stTb4b4b4)Tffd700}Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_VERBOSETb4b4b4)

Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffError loading known destinations from disk, file will be recreated on exitTa5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_ERRORTb4b4b4)
Te6edf3RNSTff7b72.Td2a8fftrace_exceptionTb4b4b4(Te6edf3eTb4b4b4)
Tff7b72elseTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffDestinations file does not exist, no known destinations loadedTa5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_VERBOSETb4b4b4)

Tf0883e@staticmethod
Tff7b72def Td2a8ff_used_destination_dataTb4b4b4(Te6edf3destination_hashTb4b4b4)Tb4b4b4:
Tff7b72with Te6edf3IdentityTff7b72.Td2a8ffknown_destinations_lockTb4b4b4:
Tff7b72if Te6edf3destination_hash Tff7b72in Te6edf3IdentityTff7b72.Td2a8ffknown_destinationsTb4b4b4:
Tff7b72if Tff7b72not Te6edf3IdentityTff7b72.Td2a8ffknown_destinationsTb4b4b4[Te6edf3destination_hashTb4b4b4]Tb4b4b4[T79c0ff4Tb4b4b4] Tff7b72< T79c0ff0Tb4b4b4:
Te6edf3IdentityTff7b72.Td2a8ffknown_destinationsTb4b4b4[Te6edf3destination_hashTb4b4b4]Tb4b4b4[T79c0ff4Tb4b4b4] Tff7b72= Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4)
Tff7b72return Tff7b72True

Tff7b72return Tff7b72False

Tf0883e@staticmethod
Tff7b72def Td2a8ff_retain_destination_dataTb4b4b4(Te6edf3destination_hashTb4b4b4)Tb4b4b4:
Tff7b72with Te6edf3IdentityTff7b72.Td2a8ffknown_destinations_lockTb4b4b4:
Tff7b72if Te6edf3destination_hash Tff7b72in Te6edf3IdentityTff7b72.Td2a8ffknown_destinationsTb4b4b4:
Te6edf3IdentityTff7b72.Td2a8ffknown_destinationsTb4b4b4[Te6edf3destination_hashTb4b4b4]Tb4b4b4[T79c0ff4Tb4b4b4] Tff7b72= Tff7b72-T79c0ff1
Tff7b72return Tff7b72True

Tff7b72return Tff7b72False

Tf0883e@staticmethod
Tff7b72def Td2a8ff_unretain_destination_dataTb4b4b4(Te6edf3destination_hashTb4b4b4)Tb4b4b4:
Tff7b72with Te6edf3IdentityTff7b72.Td2a8ffknown_destinations_lockTb4b4b4:
Tff7b72if Te6edf3destination_hash Tff7b72in Te6edf3IdentityTff7b72.Td2a8ffknown_destinationsTb4b4b4:
Te6edf3IdentityTff7b72.Td2a8ffknown_destinationsTb4b4b4[Te6edf3destination_hashTb4b4b4]Tb4b4b4[T79c0ff4Tb4b4b4] Tff7b72= Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4)
Tff7b72return Tff7b72True

Tff7b72return Tff7b72False

Tf0883e@staticmethod
Tff7b72def Td2a8ff_retain_identityTb4b4b4(Te6edf3identity_hashTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3retained Tff7b72= Tff7b72False
Tff7b72with Te6edf3IdentityTff7b72.Td2a8ffknown_destinations_lockTb4b4b4: Te6edf3destination_hashes Tff7b72= Tffa657listTb4b4b4(Te6edf3IdentityTff7b72.Td2a8ffknown_destinationsTff7b72.Td2a8ffkeysTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72for Te6edf3destination_hash Tff7b72in Te6edf3destination_hashesTb4b4b4:
Te6edf3entry Tff7b72= Te6edf3IdentityTff7b72.Td2a8ffknown_destinationsTff7b72.Td2a8ffgetTb4b4b4(Te6edf3destination_hashTb4b4b4)
Tff7b72if Tff7b72not Te6edf3entryTb4b4b4: Tff7b72continue
Tff7b72if Te6edf3identity_hash Tff7b72== Te6edf3IdentityTff7b72.Td2a8fftruncated_hashTb4b4b4(Te6edf3entryTb4b4b4[T79c0ff2Tb4b4b4]Tb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3IdentityTff7b72.Td2a8ff_retain_destination_dataTb4b4b4(Te6edf3destination_hashTb4b4b4)Tb4b4b4: Te6edf3retained Tff7b72= Tff7b72True

Tff7b72return Te6edf3retained

Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4: Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffError while retaining identity Tffd700{Te6edf3RNSTff7b72.Td2a8ffprettyhexrepTb4b4b4(Te6edf3identity_hashTb4b4b4)Tffd700}Ta5d6ff: Tffd700{Te6edf3eTffd700}Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_ERRORTb4b4b4)
Tf0883e@staticmethod
Tff7b72def Td2a8ffclean_known_destinationsTb4b4b4(Te6edf3backgroundTff7b72=Tff7b72FalseTb4b4b4)Tb4b4b4:
Te6edf3now Tff7b72= Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4)
Te6edf3st Tff7b72= Te6edf3now
Te6edf3total Tff7b72= Tffa657lenTb4b4b4(Te6edf3IdentityTff7b72.Td2a8ffknown_destinationsTb4b4b4)
Te6edf3stale Tff7b72= Tb4b4b4[Tb4b4b4]
Te6edf3no_path Tff7b72= T79c0ff0
Te6edf3retained Tff7b72= T79c0ff0
Te6edf3never_used Tff7b72= T79c0ff0
Te6edf3ratchetdir Tff7b72= Te6edf3RNSTff7b72.Td2a8ffReticulumTff7b72.Td2a8ffstoragepathTff7b72+Ta5d6ff"Ta5d6ff/ratchetsTa5d6ff"

Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffCleaning known destinationsTffd700{Ta5d6ff'Ta5d6ff at background priorityTa5d6ff' Tff7b72if Te6edf3background Tff7b72else Ta5d6ff'Ta5d6ff'Tffd700}Ta5d6ff...Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4) Tff7b72if Te6edf3RNSTff7b72.Td2a8ffslTb4b4b4(Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4) Tff7b72else Tff7b72None

Tff7b72with Te6edf3IdentityTff7b72.Td2a8ffknown_destinations_lockTb4b4b4: Te6edf3destination_hashes Tff7b72= Tffa657listTb4b4b4(Te6edf3IdentityTff7b72.Td2a8ffknown_destinationsTff7b72.Td2a8ffkeysTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72for Te6edf3destination_hash Tff7b72in Te6edf3destination_hashesTb4b4b4:
Tff7b72tryTb4b4b4:
Tff7b72if Te6edf3backgroundTb4b4b4: Te6edf3timeTff7b72.Td2a8ffsleepTb4b4b4(T79c0ff0.001Tb4b4b4) T8b949e# Low priority, yield thread
Te6edf3RNSTff7b72.Td2a8ffTransportTff7b72.Td2a8ffdestinations_last_cleaned Tff7b72= Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4)
Tff7b72if Te6edf3RNSTff7b72.Td2a8ffTransportTff7b72.Td2a8ffhas_pathTb4b4b4(Te6edf3destination_hashTb4b4b4)Tb4b4b4: Te6edf3has_path Tff7b72= Tff7b72True
Tff7b72elseTb4b4b4:
Te6edf3has_path Tff7b72= Tff7b72False
Te6edf3no_path Tff7b72+Tff7b72= T79c0ff1

Tff7b72with Te6edf3IdentityTff7b72.Td2a8ffknown_destinations_lockTb4b4b4:
Tff7b72if Te6edf3destination_hash Tff7b72in Te6edf3IdentityTff7b72.Td2a8ffknown_destinationsTb4b4b4:
Te6edf3last_announce Tff7b72= Te6edf3IdentityTff7b72.Td2a8ffknown_destinationsTb4b4b4[Te6edf3destination_hashTb4b4b4]Tb4b4b4[T79c0ff0Tb4b4b4]
Te6edf3last_use Tff7b72= T79c0ff0
Te6edf3was_used Tff7b72= Tff7b72False
Te6edf3is_retained Tff7b72= Tff7b72False

Tff7b72if Te6edf3IdentityTff7b72.Td2a8ffknown_destinationsTb4b4b4[Te6edf3destination_hashTb4b4b4]Tb4b4b4[T79c0ff4Tb4b4b4] Tff7b72> T79c0ff0Tb4b4b4:
Te6edf3was_used Tff7b72= Tff7b72True
Te6edf3last_use Tff7b72= Te6edf3IdentityTff7b72.Td2a8ffknown_destinationsTb4b4b4[Te6edf3destination_hashTb4b4b4]Tb4b4b4[T79c0ff4Tb4b4b4]

Tff7b72elif Te6edf3IdentityTff7b72.Td2a8ffknown_destinationsTb4b4b4[Te6edf3destination_hashTb4b4b4]Tb4b4b4[T79c0ff4Tb4b4b4] Tff7b72== T79c0ff0Tb4b4b4:
Te6edf3was_used Tff7b72= Tff7b72False
Te6edf3never_used Tff7b72+Tff7b72= T79c0ff1

Tff7b72elif Te6edf3IdentityTff7b72.Td2a8ffknown_destinationsTb4b4b4[Te6edf3destination_hashTb4b4b4]Tb4b4b4[T79c0ff4Tb4b4b4] Tff7b72== Tff7b72-T79c0ff1Tb4b4b4:
Te6edf3is_retained Tff7b72= Tff7b72True
Te6edf3retained Tff7b72+Tff7b72= T79c0ff1

Te6edf3unused_for Tff7b72= Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4) Tff7b72- Te6edf3IdentityTff7b72.Td2a8ffknown_destinationsTb4b4b4[Te6edf3destination_hashTb4b4b4]Tb4b4b4[T79c0ff4Tb4b4b4]

Tff7b72if Tff7b72not Te6edf3is_retained Tff7b72and Tff7b72not Te6edf3has_pathTb4b4b4:
Tff7b72if Tff7b72not Te6edf3was_used Tff7b72and Te6edf3now Tff7b72- Te6edf3last_announce Tff7b72> Te6edf3RNSTff7b72.Td2a8ffTransportTff7b72.Td2a8ffUNUSED_DESTINATION_LINGERTb4b4b4: Te6edf3staleTff7b72.Td2a8ffappendTb4b4b4(Te6edf3destination_hashTb4b4b4)
Tff7b72elif Te6edf3unused_for Tff7b72> Te6edf3RNSTff7b72.Td2a8ffTransportTff7b72.Td2a8ffDESTINATION_TIMEOUTTff7b72*T79c0ff1.25Tb4b4b4: Te6edf3staleTff7b72.Td2a8ffappendTb4b4b4(Te6edf3destination_hashTb4b4b4)

Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4: Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffFaulty entry for Tffd700{Te6edf3RNSTff7b72.Td2a8ffprettyhexrepTb4b4b4(Te6edf3destination_hashTb4b4b4)Tffd700}Ta5d6ff while cleaning known destinations: Tffd700{Te6edf3eTffd700}Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4) Tff7b72if Te6edf3RNSTff7b72.Td2a8ffslTb4b4b4(Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4) Tff7b72else Tff7b72None

Te6edf3removed Tff7b72= T79c0ff0
Tff7b72for Te6edf3destination_hash Tff7b72in Te6edf3staleTb4b4b4:
Tff7b72with Te6edf3IdentityTff7b72.Td2a8ffknown_destinations_lockTb4b4b4:
Tff7b72if Te6edf3destination_hash Tff7b72in Te6edf3IdentityTff7b72.Td2a8ffknown_destinationsTb4b4b4:
Te6edf3IdentityTff7b72.Td2a8ffknown_destinationsTff7b72.Td2a8ffpopTb4b4b4(Te6edf3destination_hashTb4b4b4)
Te6edf3removed Tff7b72+Tff7b72= T79c0ff1

Tff7b72tryTb4b4b4:
Te6edf3hexhash Tff7b72= Te6edf3RNSTff7b72.Td2a8ffhexrepTb4b4b4(Te6edf3destination_hashTb4b4b4, Te6edf3delimitTff7b72=Tff7b72FalseTb4b4b4)
Te6edf3ratchet_path Tff7b72= Ta5d6fffTa5d6ff"Tffd700{Te6edf3ratchetdirTffd700}Ta5d6ff/Tffd700{Te6edf3hexhashTffd700}Ta5d6ff"
Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffisfileTb4b4b4(Te6edf3ratchet_pathTb4b4b4)Tb4b4b4: Te6edf3osTff7b72.Td2a8ffunlinkTb4b4b4(Te6edf3ratchet_pathTb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4: Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffCould not clean stale ratchets for Tffd700{Te6edf3RNSTff7b72.Td2a8ffprettyhexrepTb4b4b4(Te6edf3destination_hashTb4b4b4)Tffd700}Ta5d6ff: Tffd700{Te6edf3eTffd700}Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_WARNINGTb4b4b4)

Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffCleaned known destinations in Tffd700{Te6edf3RNSTff7b72.Td2a8ffprettyshorttimeTb4b4b4(Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4)Tff7b72-Te6edf3stTb4b4b4)Tffd700}Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4) Tff7b72if Te6edf3RNSTff7b72.Td2a8ffslTb4b4b4(Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4) Tff7b72else Tff7b72None
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffTotal: Tffd700{Te6edf3totalTffd700}Ta5d6ff, stale: Tffd700{Tffa657lenTb4b4b4(Te6edf3staleTb4b4b4)Tffd700}Ta5d6ff, removed: Tffd700{Te6edf3removedTffd700}Ta5d6ff, no path: Tffd700{Te6edf3no_pathTffd700}Ta5d6ff, never used: Tffd700{Te6edf3never_usedTffd700}Ta5d6ff, with path: Tffd700{Te6edf3totalTff7b72-Te6edf3no_pathTffd700}Ta5d6ff, used: Tffd700{Te6edf3totalTff7b72-Te6edf3never_usedTffd700}Ta5d6ff, retained: Tffd700{Te6edf3retainedTffd700}Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_PATHINGTb4b4b4) Tff7b72if Te6edf3RNSTff7b72.Td2a8ffslTb4b4b4(Te6edf3RNSTff7b72.Td2a8ffLOG_PATHINGTb4b4b4) Tff7b72else Tff7b72None
Tff7b72if Tff7b72not Te6edf3RNSTff7b72.Td2a8ffTransportTff7b72.Td2a8ffownerTff7b72.Td2a8ffis_connected_to_shared_instanceTb4b4b4: Te6edf3IdentityTff7b72.Td2a8ffsave_known_destinationsTb4b4b4(Te6edf3recombineTff7b72=Tff7b72FalseTb4b4b4)

Tf0883e@staticmethod
Tff7b72def Td2a8fffull_hashTb4b4b4(Te6edf3dataTb4b4b4)Tb4b4b4:
T8b949e"""
Get a SHA-256 hash of passed data.

:param data: Data to be hashed as *bytes*.
:returns: SHA-256 hash as *bytes*.
"""
Tff7b72return Te6edf3RNSTff7b72.Td2a8ffCryptographyTff7b72.Td2a8ffsha256Tb4b4b4(Te6edf3dataTb4b4b4)

Tf0883e@staticmethod
Tff7b72def Td2a8fftruncated_hashTb4b4b4(Te6edf3dataTb4b4b4)Tb4b4b4:
T8b949e"""
Get a truncated SHA-256 hash of passed data.

:param data: Data to be hashed as *bytes*.
:returns: Truncated SHA-256 hash as *bytes*.
"""
Tff7b72return Te6edf3IdentityTff7b72.Td2a8fffull_hashTb4b4b4(Te6edf3dataTb4b4b4)Tb4b4b4[Tb4b4b4:Tb4b4b4(Te6edf3IdentityTff7b72.Td2a8ffTRUNCATED_HASHLENGTHTff7b72/Tff7b72/T79c0ff8Tb4b4b4)Tb4b4b4]

Tf0883e@staticmethod
Tff7b72def Td2a8ffget_random_hashTb4b4b4(Tb4b4b4)Tb4b4b4:
T8b949e"""
Get a random SHA-256 hash.

:param data: Data to be hashed as *bytes*.
:returns: Truncated SHA-256 hash of random data as *bytes*.
"""
Tff7b72return Te6edf3IdentityTff7b72.Td2a8fftruncated_hashTb4b4b4(Te6edf3osTff7b72.Td2a8ffurandomTb4b4b4(Te6edf3IdentityTff7b72.Td2a8ffTRUNCATED_HASHLENGTHTff7b72/Tff7b72/T79c0ff8Tb4b4b4)Tb4b4b4)

Tf0883e@staticmethod
Tff7b72def Td2a8ffcurrent_ratchet_idTb4b4b4(Te6edf3destination_hashTb4b4b4)Tb4b4b4:
T8b949e"""
Get the ID of the currently used ratchet key for a given destination hash

:param destination_hash: A destination hash as *bytes*.
:returns: A ratchet ID as *bytes* or *None*.
"""
Te6edf3ratchet Tff7b72= Te6edf3IdentityTff7b72.Td2a8ffget_ratchetTb4b4b4(Te6edf3destination_hashTb4b4b4)
Tff7b72if Te6edf3ratchet Tff7b72== Tff7b72NoneTb4b4b4:
Tff7b72return Tff7b72None
Tff7b72elseTb4b4b4:
Tff7b72return Te6edf3IdentityTff7b72.Td2a8ff_get_ratchet_idTb4b4b4(Te6edf3ratchetTb4b4b4)

Tf0883e@staticmethod
Tff7b72def Td2a8ff_get_ratchet_idTb4b4b4(Te6edf3ratchet_pub_bytesTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3IdentityTff7b72.Td2a8fffull_hashTb4b4b4(Te6edf3ratchet_pub_bytesTb4b4b4)Tb4b4b4[Tb4b4b4:Te6edf3IdentityTff7b72.Td2a8ffNAME_HASH_LENGTHTff7b72/Tff7b72/T79c0ff8Tb4b4b4]

Tf0883e@staticmethod
Tff7b72def Td2a8ff_ratchet_public_bytesTb4b4b4(Te6edf3ratchetTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3X25519PrivateKeyTff7b72.Td2a8fffrom_private_bytesTb4b4b4(Te6edf3ratchetTb4b4b4)Tff7b72.Td2a8ffpublic_keyTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ffpublic_bytesTb4b4b4(Tb4b4b4)

Tf0883e@staticmethod
Tff7b72def Td2a8ff_generate_ratchetTb4b4b4(Tb4b4b4)Tb4b4b4:
Te6edf3ratchet_prv Tff7b72= Te6edf3X25519PrivateKeyTff7b72.Td2a8ffgenerateTb4b4b4(Tb4b4b4)
Te6edf3ratchet_pub Tff7b72= Te6edf3ratchet_prvTff7b72.Td2a8ffpublic_keyTb4b4b4(Tb4b4b4)
Tff7b72return Te6edf3ratchet_prvTff7b72.Td2a8ffprivate_bytesTb4b4b4(Tb4b4b4)

Tf0883e@staticmethod
Tff7b72def Td2a8ff_remember_ratchetTb4b4b4(Te6edf3destination_hashTb4b4b4, Te6edf3ratchetTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Tff7b72if Te6edf3destination_hash Tff7b72in Te6edf3IdentityTff7b72.Td2a8ffknown_ratchets Tff7b72and Te6edf3IdentityTff7b72.Td2a8ffknown_ratchetsTb4b4b4[Te6edf3destination_hashTb4b4b4] Tff7b72== Te6edf3ratchetTb4b4b4:
Te6edf3ratchet_exists Tff7b72= Tff7b72True
Tff7b72elseTb4b4b4:
Te6edf3ratchet_exists Tff7b72= Tff7b72False

Tff7b72if Tff7b72not Te6edf3ratchet_existsTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffRemembering ratchet Tffd700{Te6edf3RNSTff7b72.Td2a8ffprettyhexrepTb4b4b4(Te6edf3IdentityTff7b72.Td2a8ff_get_ratchet_idTb4b4b4(Te6edf3ratchetTb4b4b4)Tb4b4b4)Tffd700}Ta5d6ff for Tffd700{Te6edf3RNSTff7b72.Td2a8ffprettyhexrepTb4b4b4(Te6edf3destination_hashTb4b4b4)Tffd700}Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_EXTREMETb4b4b4) Tff7b72if Te6edf3RNSTff7b72.Td2a8ffslTb4b4b4(Te6edf3RNSTff7b72.Td2a8ffLOG_EXTREMETb4b4b4) Tff7b72else Tff7b72None
Te6edf3IdentityTff7b72.Td2a8ffknown_ratchetsTb4b4b4[Te6edf3destination_hashTb4b4b4] Tff7b72= Te6edf3ratchet
Tff7b72if Tff7b72not Te6edf3RNSTff7b72.Td2a8ffTransportTff7b72.Td2a8ffownerTff7b72.Td2a8ffis_connected_to_shared_instanceTb4b4b4:
Tff7b72def Td2a8ffpersist_jobTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72with Te6edf3IdentityTff7b72.Td2a8ffratchet_persist_lockTb4b4b4:
Te6edf3hexhash Tff7b72= Te6edf3RNSTff7b72.Td2a8ffhexrepTb4b4b4(Te6edf3destination_hashTb4b4b4, Te6edf3delimitTff7b72=Tff7b72FalseTb4b4b4)
Te6edf3ratchet_data Tff7b72= Tb4b4b4{Ta5d6ff"Ta5d6ffratchetTa5d6ff"Tb4b4b4: Te6edf3ratchetTb4b4b4, Ta5d6ff"Ta5d6ffreceivedTa5d6ff"Tb4b4b4: Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4)Tb4b4b4}

Te6edf3ratchetdir Tff7b72= Te6edf3RNSTff7b72.Td2a8ffReticulumTff7b72.Td2a8ffstoragepathTff7b72+Ta5d6ff"Ta5d6ff/ratchetsTa5d6ff"
Tff7b72if Tff7b72not Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffisdirTb4b4b4(Te6edf3ratchetdirTb4b4b4)Tb4b4b4:
Te6edf3osTff7b72.Td2a8ffmakedirsTb4b4b4(Te6edf3ratchetdirTb4b4b4)

Te6edf3outpath Tff7b72= Ta5d6fffTa5d6ff"Tffd700{Te6edf3ratchetdirTffd700}Ta5d6ff/Tffd700{Te6edf3hexhashTffd700}Ta5d6ff.outTa5d6ff"
Te6edf3finalpath Tff7b72= Ta5d6fffTa5d6ff"Tffd700{Te6edf3ratchetdirTffd700}Ta5d6ff/Tffd700{Te6edf3hexhashTffd700}Ta5d6ff"
Tff7b72with Tffa657openTb4b4b4(Te6edf3outpathTb4b4b4, Ta5d6ff"Ta5d6ffwbTa5d6ff"Tb4b4b4) Tff7b72as Te6edf3ratchet_fileTb4b4b4:
Te6edf3ratchet_fileTff7b72.Td2a8ffwriteTb4b4b4(Te6edf3umsgpackTff7b72.Td2a8ffpackbTb4b4b4(Te6edf3ratchet_dataTb4b4b4)Tb4b4b4)
Te6edf3osTff7b72.Td2a8ffreplaceTb4b4b4(Te6edf3outpathTb4b4b4, Te6edf3finalpathTb4b4b4)

Te6edf3threadingTff7b72.Td2a8ffThreadTb4b4b4(Te6edf3targetTff7b72=Te6edf3persist_jobTb4b4b4, Te6edf3daemonTff7b72=Tff7b72TrueTb4b4b4)Tff7b72.Td2a8ffstartTb4b4b4(Tb4b4b4)

Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffCould not persist ratchet for Tffd700{Te6edf3RNSTff7b72.Td2a8ffprettyhexrepTb4b4b4(Te6edf3destination_hashTb4b4b4)Tffd700}Ta5d6ff to storage.Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_ERRORTb4b4b4)
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffThe contained exception was: Tffd700{Te6edf3eTffd700}Ta5d6ff"Tb4b4b4)
Te6edf3RNSTff7b72.Td2a8fftrace_exceptionTb4b4b4(Te6edf3eTb4b4b4)

Tf0883e@staticmethod
Tff7b72def Td2a8ff_clean_ratchetsTb4b4b4(Tb4b4b4)Tb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffCleaning ratchets...Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4) Tff7b72if Te6edf3RNSTff7b72.Td2a8ffslTb4b4b4(Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4) Tff7b72else Tff7b72None
Tff7b72tryTb4b4b4:
Te6edf3count Tff7b72= T79c0ff0
Te6edf3removed Tff7b72= T79c0ff0
Te6edf3not_known Tff7b72= T79c0ff0
Te6edf3now Tff7b72= Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4)
Te6edf3ratchetdir Tff7b72= Te6edf3RNSTff7b72.Td2a8ffReticulumTff7b72.Td2a8ffstoragepathTff7b72+Ta5d6ff"Ta5d6ff/ratchetsTa5d6ff"
Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffisdirTb4b4b4(Te6edf3ratchetdirTb4b4b4)Tb4b4b4:
Tff7b72for Te6edf3filename Tff7b72in Te6edf3osTff7b72.Td2a8fflistdirTb4b4b4(Te6edf3ratchetdirTb4b4b4)Tb4b4b4:
Te6edf3count Tff7b72+Tff7b72= T79c0ff1
Tff7b72tryTb4b4b4:
Te6edf3expired Tff7b72= Tff7b72False
Te6edf3corrupted Tff7b72= Tff7b72False
Tff7b72with Tffa657openTb4b4b4(Ta5d6fffTa5d6ff"Tffd700{Te6edf3ratchetdirTffd700}Ta5d6ff/Tffd700{Te6edf3filenameTffd700}Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffrbTa5d6ff"Tb4b4b4) Tff7b72as Te6edf3rfTb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3ratchet_data Tff7b72= Te6edf3umsgpackTff7b72.Td2a8ffunpackbTb4b4b4(Te6edf3rfTff7b72.Td2a8ffreadTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72if Te6edf3now Tff7b72> Te6edf3ratchet_dataTb4b4b4[Ta5d6ff"Ta5d6ffreceivedTa5d6ff"Tb4b4b4]Tff7b72+Te6edf3IdentityTff7b72.Td2a8ffRATCHET_EXPIRYTb4b4b4: Te6edf3expired Tff7b72= Tff7b72True

Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffCorrupted ratchet data while reading Tffd700{Te6edf3ratchetdirTffd700}Ta5d6ff/Tffd700{Te6edf3filenameTffd700}Ta5d6ff, removing fileTa5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_ERRORTb4b4b4)
Te6edf3corrupted Tff7b72= Tff7b72True

Te6edf3destination_hash Tff7b72= Tffa657bytesTff7b72.Td2a8fffromhexTb4b4b4(Te6edf3filenameTb4b4b4)
Tff7b72if Tff7b72not Te6edf3destination_hash Tff7b72in Te6edf3RNSTff7b72.Td2a8ffIdentityTff7b72.Td2a8ffknown_destinationsTb4b4b4: Te6edf3unknown Tff7b72= Tff7b72TrueTb4b4b4; Te6edf3not_known Tff7b72+Tff7b72= T79c0ff1
Tff7b72elseTb4b4b4: Te6edf3unknown Tff7b72= Tff7b72False

Tff7b72if Te6edf3expired Tff7b72or Te6edf3corrupted Tff7b72or Te6edf3unknownTb4b4b4:
Te6edf3osTff7b72.Td2a8ffunlinkTb4b4b4(Ta5d6fffTa5d6ff"Tffd700{Te6edf3ratchetdirTffd700}Ta5d6ff/Tffd700{Te6edf3filenameTffd700}Ta5d6ff"Tb4b4b4)
Te6edf3removed Tff7b72+Tff7b72= T79c0ff1

Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffAn error occurred while cleaning ratchets, in the processing of Tffd700{Te6edf3ratchetdirTffd700}Ta5d6ff/Tffd700{Te6edf3filenameTffd700}Ta5d6ff.Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_ERRORTb4b4b4)
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffThe contained exception was: Tffd700{Te6edf3eTffd700}Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_ERRORTb4b4b4)

Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4: Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffAn error occurred while cleaning ratchets. The contained exception was: Tffd700{Te6edf3eTffd700}Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_ERRORTb4b4b4)
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffProcessed Tffd700{Te6edf3countTffd700}Ta5d6ff ratchets in Tffd700{Te6edf3RNSTff7b72.Td2a8ffprettytimeTb4b4b4(Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4)Tff7b72-Te6edf3nowTb4b4b4)Tffd700}Ta5d6ff, not in use Tffd700{Te6edf3not_knownTffd700}Ta5d6ff, removed Tffd700{Te6edf3removedTffd700}Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4) Tff7b72if Te6edf3RNSTff7b72.Td2a8ffslTb4b4b4(Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4) Tff7b72else Tff7b72None

Tf0883e@staticmethod
Tff7b72def Td2a8ffget_ratchetTb4b4b4(Te6edf3destination_hashTb4b4b4)Tb4b4b4:
Tff7b72if Tff7b72not Te6edf3destination_hash Tff7b72in Te6edf3IdentityTff7b72.Td2a8ffknown_ratchetsTb4b4b4:
Te6edf3ratchetdir Tff7b72= Te6edf3RNSTff7b72.Td2a8ffReticulumTff7b72.Td2a8ffstoragepathTff7b72+Ta5d6ff"Ta5d6ff/ratchetsTa5d6ff"
Te6edf3hexhash Tff7b72= Te6edf3RNSTff7b72.Td2a8ffhexrepTb4b4b4(Te6edf3destination_hashTb4b4b4, Te6edf3delimitTff7b72=Tff7b72FalseTb4b4b4)
Te6edf3ratchet_path Tff7b72= Ta5d6fffTa5d6ff"Tffd700{Te6edf3ratchetdirTffd700}Ta5d6ff/Tffd700{Te6edf3hexhashTffd700}Ta5d6ff"
Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffisfileTb4b4b4(Te6edf3ratchet_pathTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Tff7b72with Tffa657openTb4b4b4(Te6edf3ratchet_pathTb4b4b4, Ta5d6ff"Ta5d6ffrbTa5d6ff"Tb4b4b4) Tff7b72as Te6edf3ratchet_fileTb4b4b4:
Te6edf3ratchet_data Tff7b72= Te6edf3umsgpackTff7b72.Td2a8ffunpackbTb4b4b4(Te6edf3ratchet_fileTff7b72.Td2a8ffreadTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72if Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4) Tff7b72< Te6edf3ratchet_dataTb4b4b4[Ta5d6ff"Ta5d6ffreceivedTa5d6ff"Tb4b4b4]Tff7b72+Te6edf3IdentityTff7b72.Td2a8ffRATCHET_EXPIRY Tff7b72and Tffa657lenTb4b4b4(Te6edf3ratchet_dataTb4b4b4[Ta5d6ff"Ta5d6ffratchetTa5d6ff"Tb4b4b4]Tb4b4b4) Tff7b72== Te6edf3IdentityTff7b72.Td2a8ffRATCHETSIZETff7b72/Tff7b72/T79c0ff8Tb4b4b4:
Te6edf3IdentityTff7b72.Td2a8ffknown_ratchetsTb4b4b4[Te6edf3destination_hashTb4b4b4] Tff7b72= Te6edf3ratchet_dataTb4b4b4[Ta5d6ff"Ta5d6ffratchetTa5d6ff"Tb4b4b4]
Tff7b72elseTb4b4b4:
Tff7b72return Tff7b72None
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffAn error occurred while loading ratchet data for Tffd700{Te6edf3RNSTff7b72.Td2a8ffprettyhexrepTb4b4b4(Te6edf3destination_hashTb4b4b4)Tffd700}Ta5d6ff from storage.Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_ERRORTb4b4b4)
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffThe contained exception was: Tffd700{Te6edf3eTffd700}Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_ERRORTb4b4b4)
Tff7b72return Tff7b72None

Tff7b72if Te6edf3destination_hash Tff7b72in Te6edf3IdentityTff7b72.Td2a8ffknown_ratchetsTb4b4b4:
Tff7b72return Te6edf3IdentityTff7b72.Td2a8ffknown_ratchetsTb4b4b4[Te6edf3destination_hashTb4b4b4]
Tff7b72elseTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffCould not load ratchet for Tffd700{Te6edf3RNSTff7b72.Td2a8ffprettyhexrepTb4b4b4(Te6edf3destination_hashTb4b4b4)Tffd700}Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4) Tff7b72if Te6edf3RNSTff7b72.Td2a8ffslTb4b4b4(Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4) Tff7b72else Tff7b72None
Tff7b72return Tff7b72None

Tf0883e@staticmethod
Tff7b72def Td2a8ffvalidate_announceTb4b4b4(Te6edf3packetTb4b4b4, Te6edf3only_validate_signatureTff7b72=Tff7b72FalseTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Tff7b72if Te6edf3packetTff7b72.Td2a8ffpacket_type Tff7b72== Te6edf3RNSTff7b72.Td2a8ffPacketTff7b72.Td2a8ffANNOUNCETb4b4b4:
Te6edf3keysize Tff7b72= Te6edf3IdentityTff7b72.Td2a8ffKEYSIZETff7b72/Tff7b72/T79c0ff8
Te6edf3ratchetsize Tff7b72= Te6edf3IdentityTff7b72.Td2a8ffRATCHETSIZETff7b72/Tff7b72/T79c0ff8
Te6edf3name_hash_len Tff7b72= Te6edf3IdentityTff7b72.Td2a8ffNAME_HASH_LENGTHTff7b72/Tff7b72/T79c0ff8
Te6edf3sig_len Tff7b72= Te6edf3IdentityTff7b72.Td2a8ffSIGLENGTHTff7b72/Tff7b72/T79c0ff8
Te6edf3destination_hash Tff7b72= Te6edf3packetTff7b72.Td2a8ffdestination_hash

T8b949e# Get public key bytes from announce
Te6edf3public_key Tff7b72= Te6edf3packetTff7b72.Td2a8ffdataTb4b4b4[Tb4b4b4:Te6edf3keysizeTb4b4b4]

T8b949e# If the packet context flag is set,
T8b949e# this announce contains a new ratchet
Tff7b72if Te6edf3packetTff7b72.Td2a8ffcontext_flag Tff7b72== Te6edf3RNSTff7b72.Td2a8ffPacketTff7b72.Td2a8ffFLAG_SETTb4b4b4:
Te6edf3name_hash Tff7b72= Te6edf3packetTff7b72.Td2a8ffdataTb4b4b4[Te6edf3keysizeTb4b4b4:Te6edf3keysizeTff7b72+Te6edf3name_hash_len Tb4b4b4]
Te6edf3random_hash Tff7b72= Te6edf3packetTff7b72.Td2a8ffdataTb4b4b4[Te6edf3keysizeTff7b72+Te6edf3name_hash_lenTb4b4b4:Te6edf3keysizeTff7b72+Te6edf3name_hash_lenTff7b72+T79c0ff10Tb4b4b4]
Te6edf3ratchet Tff7b72= Te6edf3packetTff7b72.Td2a8ffdataTb4b4b4[Te6edf3keysizeTff7b72+Te6edf3name_hash_lenTff7b72+T79c0ff10Tb4b4b4:Te6edf3keysizeTff7b72+Te6edf3name_hash_lenTff7b72+T79c0ff10Tff7b72+Te6edf3ratchetsizeTb4b4b4]
Te6edf3signature Tff7b72= Te6edf3packetTff7b72.Td2a8ffdataTb4b4b4[Te6edf3keysizeTff7b72+Te6edf3name_hash_lenTff7b72+T79c0ff10Tff7b72+Te6edf3ratchetsizeTb4b4b4:Te6edf3keysizeTff7b72+Te6edf3name_hash_lenTff7b72+T79c0ff10Tff7b72+Te6edf3ratchetsizeTff7b72+Te6edf3sig_lenTb4b4b4]
Te6edf3app_data Tff7b72= Ta5d6ffbTa5d6ff"Ta5d6ff"
Tff7b72if Tffa657lenTb4b4b4(Te6edf3packetTff7b72.Td2a8ffdataTb4b4b4) Tff7b72> Te6edf3keysizeTff7b72+Te6edf3name_hash_lenTff7b72+T79c0ff10Tff7b72+Te6edf3sig_lenTff7b72+Te6edf3ratchetsizeTb4b4b4:
Te6edf3app_data Tff7b72= Te6edf3packetTff7b72.Td2a8ffdataTb4b4b4[Te6edf3keysizeTff7b72+Te6edf3name_hash_lenTff7b72+T79c0ff10Tff7b72+Te6edf3sig_lenTff7b72+Te6edf3ratchetsizeTb4b4b4:Tb4b4b4]

T8b949e# If the packet context flag is not set,
T8b949e# this announce does not contain a ratchet
Tff7b72elseTb4b4b4:
Te6edf3ratchet Tff7b72= Ta5d6ffbTa5d6ff"Ta5d6ff"
Te6edf3name_hash Tff7b72= Te6edf3packetTff7b72.Td2a8ffdataTb4b4b4[Te6edf3keysizeTb4b4b4:Te6edf3keysizeTff7b72+Te6edf3name_hash_lenTb4b4b4]
Te6edf3random_hash Tff7b72= Te6edf3packetTff7b72.Td2a8ffdataTb4b4b4[Te6edf3keysizeTff7b72+Te6edf3name_hash_lenTb4b4b4:Te6edf3keysizeTff7b72+Te6edf3name_hash_lenTff7b72+T79c0ff10Tb4b4b4]
Te6edf3signature Tff7b72= Te6edf3packetTff7b72.Td2a8ffdataTb4b4b4[Te6edf3keysizeTff7b72+Te6edf3name_hash_lenTff7b72+T79c0ff10Tb4b4b4:Te6edf3keysizeTff7b72+Te6edf3name_hash_lenTff7b72+T79c0ff10Tff7b72+Te6edf3sig_lenTb4b4b4]
Te6edf3app_data Tff7b72= Ta5d6ffbTa5d6ff"Ta5d6ff"
Tff7b72if Tffa657lenTb4b4b4(Te6edf3packetTff7b72.Td2a8ffdataTb4b4b4) Tff7b72> Te6edf3keysizeTff7b72+Te6edf3name_hash_lenTff7b72+T79c0ff10Tff7b72+Te6edf3sig_lenTb4b4b4:
Te6edf3app_data Tff7b72= Te6edf3packetTff7b72.Td2a8ffdataTb4b4b4[Te6edf3keysizeTff7b72+Te6edf3name_hash_lenTff7b72+T79c0ff10Tff7b72+Te6edf3sig_lenTb4b4b4:Tb4b4b4]

Te6edf3signed_data Tff7b72= Te6edf3destination_hashTff7b72+Te6edf3public_keyTff7b72+Te6edf3name_hashTff7b72+Te6edf3random_hashTff7b72+Te6edf3ratchetTff7b72+Te6edf3app_data

Tff7b72if Tff7b72not Tffa657lenTb4b4b4(Te6edf3packetTff7b72.Td2a8ffdataTb4b4b4) Tff7b72> Te6edf3IdentityTff7b72.Td2a8ffKEYSIZETff7b72/Tff7b72/T79c0ff8Tff7b72+Te6edf3IdentityTff7b72.Td2a8ffNAME_HASH_LENGTHTff7b72/Tff7b72/T79c0ff8Tff7b72+T79c0ff10Tff7b72+Te6edf3IdentityTff7b72.Td2a8ffSIGLENGTHTff7b72/Tff7b72/T79c0ff8Tb4b4b4:
Te6edf3app_data Tff7b72= Tff7b72None

Te6edf3announced_identity Tff7b72= Te6edf3IdentityTb4b4b4(Te6edf3create_keysTff7b72=Tff7b72FalseTb4b4b4)
Te6edf3announced_identityTff7b72.Td2a8ffload_public_keyTb4b4b4(Te6edf3public_keyTb4b4b4)

Tff7b72if Tffa657lenTb4b4b4(Te6edf3RNSTff7b72.Td2a8ffTransportTff7b72.Td2a8ffblackholed_identitiesTb4b4b4) Tff7b72> T79c0ff0Tb4b4b4:
Tff7b72if Te6edf3announced_identityTff7b72.Td2a8ffhash Tff7b72in Te6edf3RNSTff7b72.Td2a8ffTransportTff7b72.Td2a8ffblackholed_identitiesTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffInvalidated and dropped announce from blackholed identity Tffd700{Te6edf3RNSTff7b72.Td2a8ffprettyhexrepTb4b4b4(Te6edf3announced_identityTff7b72.Td2a8ffhashTb4b4b4)Tffd700}Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_EXTREMETb4b4b4) Tff7b72if Te6edf3RNSTff7b72.Td2a8ffslTb4b4b4(Te6edf3RNSTff7b72.Td2a8ffLOG_EXTREMETb4b4b4) Tff7b72else Tff7b72None
Tff7b72return Tff7b72False

Tff7b72if Te6edf3announced_identityTff7b72.Td2a8ffpub Tff7b72!= Tff7b72None Tff7b72and Te6edf3announced_identityTff7b72.Td2a8ffvalidateTb4b4b4(Te6edf3signatureTb4b4b4, Te6edf3signed_dataTb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3only_validate_signatureTb4b4b4:
Tff7b72del Te6edf3announced_identity
Tff7b72return Tff7b72True

Te6edf3hash_material Tff7b72= Te6edf3name_hashTff7b72+Te6edf3announced_identityTff7b72.Td2a8ffhash
Te6edf3expected_hash Tff7b72= Te6edf3RNSTff7b72.Td2a8ffIdentityTff7b72.Td2a8fffull_hashTb4b4b4(Te6edf3hash_materialTb4b4b4)Tb4b4b4[Tb4b4b4:Te6edf3RNSTff7b72.Td2a8ffReticulumTff7b72.Td2a8ffTRUNCATED_HASHLENGTHTff7b72/Tff7b72/T79c0ff8Tb4b4b4]

Tff7b72if Te6edf3destination_hash Tff7b72== Te6edf3expected_hashTb4b4b4:
T8b949e# Check if we already have a public key for this destination
T8b949e# and make sure the public key is not different.
Tff7b72if Te6edf3destination_hash Tff7b72in Te6edf3IdentityTff7b72.Td2a8ffknown_destinationsTb4b4b4:
Tff7b72if Te6edf3public_key Tff7b72!= Te6edf3IdentityTff7b72.Td2a8ffknown_destinationsTb4b4b4[Te6edf3destination_hashTb4b4b4]Tb4b4b4[T79c0ff2Tb4b4b4]Tb4b4b4:
T8b949e# In reality, this should never occur, but in the odd case
T8b949e# that someone manages a hash collision, we reject the announce.
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffReceived announce with valid signature and destination hash, but announced public key does not match already known public key.Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_CRITICALTb4b4b4)
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffThis may indicate an attempt to modify network paths, or a random hash collision. The announce was rejected.Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_CRITICALTb4b4b4)
Tff7b72return Tff7b72False

Te6edf3RNSTff7b72.Td2a8ffIdentityTff7b72.Td2a8ffrememberTb4b4b4(Te6edf3packetTff7b72.Td2a8ffget_hashTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3destination_hashTb4b4b4, Te6edf3public_keyTb4b4b4, Te6edf3app_dataTb4b4b4)
Tff7b72del Te6edf3announced_identity

Tff7b72if Te6edf3packetTff7b72.Td2a8ffrssi Tff7b72!= Tff7b72None Tff7b72or Te6edf3packetTff7b72.Td2a8ffsnr Tff7b72!= Tff7b72NoneTb4b4b4:
Te6edf3signal_str Tff7b72= Ta5d6ff"Ta5d6ff [Ta5d6ff"
Tff7b72if Te6edf3packetTff7b72.Td2a8ffrssi Tff7b72!= Tff7b72NoneTb4b4b4:
Te6edf3signal_str Tff7b72+Tff7b72= Ta5d6ff"Ta5d6ffRSSI Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Te6edf3packetTff7b72.Td2a8ffrssiTb4b4b4)Tff7b72+Ta5d6ff"Ta5d6ffdBmTa5d6ff"
Tff7b72if Te6edf3packetTff7b72.Td2a8ffsnr Tff7b72!= Tff7b72NoneTb4b4b4: Te6edf3signal_str Tff7b72+Tff7b72= Ta5d6ff"Ta5d6ff, Ta5d6ff"
Tff7b72if Te6edf3packetTff7b72.Td2a8ffsnr Tff7b72!= Tff7b72NoneTb4b4b4: Te6edf3signal_str Tff7b72+Tff7b72= Ta5d6ff"Ta5d6ffSNR Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Te6edf3packetTff7b72.Td2a8ffsnrTb4b4b4)Tff7b72+Ta5d6ff"Ta5d6ffdBTa5d6ff"
Te6edf3signal_str Tff7b72+Tff7b72= Ta5d6ff"Ta5d6ff]Ta5d6ff"

Tff7b72elseTb4b4b4: Te6edf3signal_str Tff7b72= Ta5d6ff"Ta5d6ff"

Tff7b72if Tffa657hasattrTb4b4b4(Te6edf3packetTb4b4b4, Ta5d6ff"Ta5d6fftransport_idTa5d6ff"Tb4b4b4) Tff7b72and Te6edf3packetTff7b72.Td2a8fftransport_id Tff7b72!= Tff7b72NoneTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffValid announce for Ta5d6ff"Tff7b72+Te6edf3RNSTff7b72.Td2a8ffprettyhexrepTb4b4b4(Te6edf3destination_hashTb4b4b4)Tff7b72+Ta5d6ff"Ta5d6ff Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Te6edf3packetTff7b72.Td2a8ffhopsTb4b4b4)Tff7b72+Ta5d6ff"Ta5d6ff hops away, received via Ta5d6ff"Tff7b72+Te6edf3RNSTff7b72.Td2a8ffprettyhexrepTb4b4b4(Te6edf3packetTff7b72.Td2a8fftransport_idTb4b4b4)Tff7b72+Ta5d6ff"Ta5d6ff on Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Te6edf3packetTff7b72.Td2a8ffreceiving_interfaceTb4b4b4)Tff7b72+Te6edf3signal_strTb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_EXTREMETb4b4b4) Tff7b72if Te6edf3RNSTff7b72.Td2a8ffslTb4b4b4(Te6edf3RNSTff7b72.Td2a8ffLOG_EXTREMETb4b4b4) Tff7b72else Tff7b72None
Tff7b72elseTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffValid announce for Ta5d6ff"Tff7b72+Te6edf3RNSTff7b72.Td2a8ffprettyhexrepTb4b4b4(Te6edf3destination_hashTb4b4b4)Tff7b72+Ta5d6ff"Ta5d6ff Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Te6edf3packetTff7b72.Td2a8ffhopsTb4b4b4)Tff7b72+Ta5d6ff"Ta5d6ff hops away, received on Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Te6edf3packetTff7b72.Td2a8ffreceiving_interfaceTb4b4b4)Tff7b72+Te6edf3signal_strTb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_EXTREMETb4b4b4) Tff7b72if Te6edf3RNSTff7b72.Td2a8ffslTb4b4b4(Te6edf3RNSTff7b72.Td2a8ffLOG_EXTREMETb4b4b4) Tff7b72else Tff7b72None

Tff7b72if Te6edf3ratchetTb4b4b4: Te6edf3IdentityTff7b72.Td2a8ff_remember_ratchetTb4b4b4(Te6edf3destination_hashTb4b4b4, Te6edf3ratchetTb4b4b4)

Tff7b72return Tff7b72True

Tff7b72elseTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffReceived invalid announce for Ta5d6ff"Tff7b72+Te6edf3RNSTff7b72.Td2a8ffprettyhexrepTb4b4b4(Te6edf3destination_hashTb4b4b4)Tff7b72+Ta5d6ff"Ta5d6ff: Destination mismatch.Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4) Tff7b72if Te6edf3RNSTff7b72.Td2a8ffslTb4b4b4(Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4) Tff7b72else Tff7b72None
Tff7b72return Tff7b72False

Tff7b72elseTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffReceived invalid announce for Ta5d6ff"Tff7b72+Te6edf3RNSTff7b72.Td2a8ffprettyhexrepTb4b4b4(Te6edf3destination_hashTb4b4b4)Tff7b72+Ta5d6ff"Ta5d6ff: Invalid signature.Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4) Tff7b72if Te6edf3RNSTff7b72.Td2a8ffslTb4b4b4(Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4) Tff7b72else Tff7b72None
Tff7b72del Te6edf3announced_identity
Tff7b72return Tff7b72False
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffError occurred while validating announce. The contained exception was: Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_ERRORTb4b4b4)
Tff7b72return Tff7b72False

Tf0883e@staticmethod
Tff7b72def Td2a8ffpersist_dataTb4b4b4(Te6edf3backgroundTff7b72=Tff7b72FalseTb4b4b4)Tb4b4b4:
Tff7b72if Tff7b72not Te6edf3RNSTff7b72.Td2a8ffTransportTff7b72.Td2a8ffownerTff7b72.Td2a8ffis_connected_to_shared_instanceTb4b4b4:
Te6edf3IdentityTff7b72.Td2a8ffsave_known_destinationsTb4b4b4(Te6edf3backgroundTff7b72=Te6edf3backgroundTb4b4b4)

Tf0883e@staticmethod
Tff7b72def Td2a8ffexit_handlerTb4b4b4(Tb4b4b4)Tb4b4b4:
Te6edf3IdentityTff7b72.Td2a8ffpersist_dataTb4b4b4(Tb4b4b4)


Tf0883e@staticmethod
Tff7b72def Td2a8fffrom_bytesTb4b4b4(Te6edf3prv_bytesTb4b4b4)Tb4b4b4:
T8b949e"""
Create a new :ref:`RNS.Identity<api-identity>` instance from *bytes* of private key.
Can be used to load previously created and saved identities into Reticulum.

:param prv_bytes: The *bytes* of private a saved private key. **HAZARD!** Never use this to generate a new key by feeding random data in prv_bytes.
:returns: A :ref:`RNS.Identity<api-identity>` instance, or *None* if the *bytes* data was invalid.
"""
Te6edf3identity Tff7b72= Te6edf3IdentityTb4b4b4(Te6edf3create_keysTff7b72=Tff7b72FalseTb4b4b4)
Tff7b72if Te6edf3identityTff7b72.Td2a8ffload_private_keyTb4b4b4(Te6edf3prv_bytesTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3identity
Tff7b72elseTb4b4b4:
Tff7b72return Tff7b72None


Tf0883e@staticmethod
Tff7b72def Td2a8fffrom_fileTb4b4b4(Te6edf3pathTb4b4b4)Tb4b4b4:
T8b949e"""
Create a new :ref:`RNS.Identity<api-identity>` instance from a file.
Can be used to load previously created and saved identities into Reticulum.

:param path: The full path to the saved :ref:`RNS.Identity<api-identity>` data
:returns: A :ref:`RNS.Identity<api-identity>` instance, or *None* if the loaded data was invalid.
"""
Te6edf3identity Tff7b72= Te6edf3IdentityTb4b4b4(Te6edf3create_keysTff7b72=Tff7b72FalseTb4b4b4)
Tff7b72if Te6edf3identityTff7b72.Td2a8ffloadTb4b4b4(Te6edf3pathTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3identity
Tff7b72elseTb4b4b4:
Tff7b72return Tff7b72None

Tff7b72def Td2a8ffto_fileTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3pathTb4b4b4)Tb4b4b4:
T8b949e"""
Saves the identity to a file. This will write the private key to disk,
and anyone with access to this file will be able to decrypt all
communication for the identity. Be very careful with this method.

:param path: The full path specifying where to save the identity.
:returns: True if the file was saved, otherwise False.
"""
Tff7b72tryTb4b4b4:
Tff7b72with Tffa657openTb4b4b4(Te6edf3pathTb4b4b4, Ta5d6ff"Ta5d6ffwbTa5d6ff"Tb4b4b4) Tff7b72as Te6edf3key_fileTb4b4b4:
Te6edf3key_fileTff7b72.Td2a8ffwriteTb4b4b4(Tff7b72selfTff7b72.Td2a8ffget_private_keyTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72return Tff7b72True
Tff7b72return Tff7b72False
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffError while saving identity to Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Te6edf3pathTb4b4b4)Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_ERRORTb4b4b4)
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffThe contained exception was: Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4)

Tff7b72def Td2a8ffpub_to_fileTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3pathTb4b4b4)Tb4b4b4:
T8b949e"""
Saves the public identity to a file.

:param path: The full path specifying where to save the identity.
:returns: True if the file was saved, otherwise False.
"""
Tff7b72tryTb4b4b4:
Tff7b72with Tffa657openTb4b4b4(Te6edf3pathTb4b4b4, Ta5d6ff"Ta5d6ffwbTa5d6ff"Tb4b4b4) Tff7b72as Te6edf3key_fileTb4b4b4:
Te6edf3key_fileTff7b72.Td2a8ffwriteTb4b4b4(Tff7b72selfTff7b72.Td2a8ffget_public_keyTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72return Tff7b72True
Tff7b72return Tff7b72False
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffError while saving identity to Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Te6edf3pathTb4b4b4)Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_ERRORTb4b4b4)
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffThe contained exception was: Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4)

Tff7b72def Tff7b72__init__Tb4b4b4(Tff7b72selfTb4b4b4,Te6edf3create_keysTff7b72=Tff7b72TrueTb4b4b4)Tb4b4b4:
T8b949e# Initialize keys to none
Tff7b72selfTff7b72.Td2a8ffprv Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ffprv_bytes Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ffsig_prv Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ffsig_prv_bytes Tff7b72= Tff7b72None

Tff7b72selfTff7b72.Td2a8ffpub Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ffpub_bytes Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ffsig_pub Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ffsig_pub_bytes Tff7b72= Tff7b72None

Tff7b72selfTff7b72.Td2a8ffhash Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ffhexhash Tff7b72= Tff7b72None

Tff7b72if Te6edf3create_keysTb4b4b4:
Tff7b72selfTff7b72.Td2a8ffcreate_keysTb4b4b4(Tb4b4b4)

Tff7b72def Td2a8ffcreate_keysTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ffprv Tff7b72= Te6edf3X25519PrivateKeyTff7b72.Td2a8ffgenerateTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffprv_bytes Tff7b72= Tff7b72selfTff7b72.Td2a8ffprvTff7b72.Td2a8ffprivate_bytesTb4b4b4(Tb4b4b4)

Tff7b72selfTff7b72.Td2a8ffsig_prv Tff7b72= Te6edf3Ed25519PrivateKeyTff7b72.Td2a8ffgenerateTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffsig_prv_bytes Tff7b72= Tff7b72selfTff7b72.Td2a8ffsig_prvTff7b72.Td2a8ffprivate_bytesTb4b4b4(Tb4b4b4)

Tff7b72selfTff7b72.Td2a8ffpub Tff7b72= Tff7b72selfTff7b72.Td2a8ffprvTff7b72.Td2a8ffpublic_keyTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffpub_bytes Tff7b72= Tff7b72selfTff7b72.Td2a8ffpubTff7b72.Td2a8ffpublic_bytesTb4b4b4(Tb4b4b4)

Tff7b72selfTff7b72.Td2a8ffsig_pub Tff7b72= Tff7b72selfTff7b72.Td2a8ffsig_prvTff7b72.Td2a8ffpublic_keyTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffsig_pub_bytes Tff7b72= Tff7b72selfTff7b72.Td2a8ffsig_pubTff7b72.Td2a8ffpublic_bytesTb4b4b4(Tb4b4b4)

Tff7b72selfTff7b72.Td2a8ffupdate_hashesTb4b4b4(Tb4b4b4)

Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffIdentity keys created for Ta5d6ff"Tff7b72+Te6edf3RNSTff7b72.Td2a8ffprettyhexrepTb4b4b4(Tff7b72selfTff7b72.Td2a8ffhashTb4b4b4)Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_VERBOSETb4b4b4)

Tff7b72def Td2a8ffget_private_keyTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""
:returns: The private key as *bytes*
"""
Tff7b72if Tff7b72selfTff7b72.Td2a8ffprv_bytes Tff7b72and Tff7b72selfTff7b72.Td2a8ffsig_prv_bytesTb4b4b4: Tff7b72return Tff7b72selfTff7b72.Td2a8ffprv_bytesTff7b72+Tff7b72selfTff7b72.Td2a8ffsig_prv_bytes
Tff7b72elseTb4b4b4: Tff7b72return Tff7b72None

Tff7b72def Td2a8ffget_public_keyTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""
:returns: The public key as *bytes*
"""
Tff7b72if Tff7b72selfTff7b72.Td2a8ffpub_bytes Tff7b72and Tff7b72selfTff7b72.Td2a8ffsig_pub_bytesTb4b4b4: Tff7b72return Tff7b72selfTff7b72.Td2a8ffpub_bytesTff7b72+Tff7b72selfTff7b72.Td2a8ffsig_pub_bytes
Tff7b72elseTb4b4b4: Tff7b72return Tff7b72None

Tff7b72def Td2a8ffload_private_keyTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3prv_bytesTb4b4b4)Tb4b4b4:
T8b949e"""
Load a private key into the instance.

:param prv_bytes: The private key as *bytes*.
:returns: True if the key was loaded, otherwise False.
"""
Tff7b72tryTb4b4b4:
Tff7b72selfTff7b72.Td2a8ffprv_bytes Tff7b72= Te6edf3prv_bytesTb4b4b4[Tb4b4b4:Te6edf3IdentityTff7b72.Td2a8ffKEYSIZETff7b72/Tff7b72/T79c0ff8Tff7b72/Tff7b72/T79c0ff2Tb4b4b4]
Tff7b72selfTff7b72.Td2a8ffprv Tff7b72= Te6edf3X25519PrivateKeyTff7b72.Td2a8fffrom_private_bytesTb4b4b4(Tff7b72selfTff7b72.Td2a8ffprv_bytesTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffsig_prv_bytes Tff7b72= Te6edf3prv_bytesTb4b4b4[Te6edf3IdentityTff7b72.Td2a8ffKEYSIZETff7b72/Tff7b72/T79c0ff8Tff7b72/Tff7b72/T79c0ff2Tb4b4b4:Tb4b4b4]
Tff7b72selfTff7b72.Td2a8ffsig_prv Tff7b72= Te6edf3Ed25519PrivateKeyTff7b72.Td2a8fffrom_private_bytesTb4b4b4(Tff7b72selfTff7b72.Td2a8ffsig_prv_bytesTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffpub Tff7b72= Tff7b72selfTff7b72.Td2a8ffprvTff7b72.Td2a8ffpublic_keyTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffpub_bytes Tff7b72= Tff7b72selfTff7b72.Td2a8ffpubTff7b72.Td2a8ffpublic_bytesTb4b4b4(Tb4b4b4)

Tff7b72selfTff7b72.Td2a8ffsig_pub Tff7b72= Tff7b72selfTff7b72.Td2a8ffsig_prvTff7b72.Td2a8ffpublic_keyTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffsig_pub_bytes Tff7b72= Tff7b72selfTff7b72.Td2a8ffsig_pubTff7b72.Td2a8ffpublic_bytesTb4b4b4(Tb4b4b4)

Tff7b72selfTff7b72.Td2a8ffupdate_hashesTb4b4b4(Tb4b4b4)

Tff7b72return Tff7b72True

Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Tff7b72raise Te6edf3e
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffFailed to load identity keyTa5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_ERRORTb4b4b4)
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffThe contained exception was: Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_ERRORTb4b4b4)
Tff7b72return Tff7b72False

Tff7b72def Td2a8ffload_public_keyTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3pub_bytesTb4b4b4)Tb4b4b4:
T8b949e"""
Load a public key into the instance.

:param pub_bytes: The public key as *bytes*.
:returns: True if the key was loaded, otherwise False.
"""
Tff7b72tryTb4b4b4:
Tff7b72selfTff7b72.Td2a8ffpub_bytes Tff7b72= Te6edf3pub_bytesTb4b4b4[Tb4b4b4:Te6edf3IdentityTff7b72.Td2a8ffKEYSIZETff7b72/Tff7b72/T79c0ff8Tff7b72/Tff7b72/T79c0ff2Tb4b4b4]
Tff7b72selfTff7b72.Td2a8ffsig_pub_bytes Tff7b72= Te6edf3pub_bytesTb4b4b4[Te6edf3IdentityTff7b72.Td2a8ffKEYSIZETff7b72/Tff7b72/T79c0ff8Tff7b72/Tff7b72/T79c0ff2Tb4b4b4:Tb4b4b4]

Tff7b72selfTff7b72.Td2a8ffpub Tff7b72= Te6edf3X25519PublicKeyTff7b72.Td2a8fffrom_public_bytesTb4b4b4(Tff7b72selfTff7b72.Td2a8ffpub_bytesTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffsig_pub Tff7b72= Te6edf3Ed25519PublicKeyTff7b72.Td2a8fffrom_public_bytesTb4b4b4(Tff7b72selfTff7b72.Td2a8ffsig_pub_bytesTb4b4b4)

Tff7b72selfTff7b72.Td2a8ffupdate_hashesTb4b4b4(Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffError while loading public key, the contained exception was: Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_ERRORTb4b4b4)

Tff7b72def Td2a8ffupdate_hashesTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ffhash Tff7b72= Te6edf3IdentityTff7b72.Td2a8fftruncated_hashTb4b4b4(Tff7b72selfTff7b72.Td2a8ffget_public_keyTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffhexhash Tff7b72= Tff7b72selfTff7b72.Td2a8ffhashTff7b72.Td2a8ffhexTb4b4b4(Tb4b4b4)

Tff7b72def Td2a8ffloadTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3pathTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Tff7b72with Tffa657openTb4b4b4(Te6edf3pathTb4b4b4, Ta5d6ff"Ta5d6ffrbTa5d6ff"Tb4b4b4) Tff7b72as Te6edf3key_fileTb4b4b4:
Te6edf3prv_bytes Tff7b72= Te6edf3key_fileTff7b72.Td2a8ffreadTb4b4b4(Tb4b4b4)
Tff7b72return Tff7b72selfTff7b72.Td2a8ffload_private_keyTb4b4b4(Te6edf3prv_bytesTb4b4b4)
Tff7b72return Tff7b72False
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffError while loading identity from Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Te6edf3pathTb4b4b4)Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_ERRORTb4b4b4)
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffThe contained exception was: Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_ERRORTb4b4b4)

Tff7b72def Td2a8ffget_saltTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72selfTff7b72.Td2a8ffhash

Tff7b72def Td2a8ffget_contextTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72None

Tff7b72def Td2a8ffencryptTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3plaintextTb4b4b4, Te6edf3ratchetTff7b72=Tff7b72NoneTb4b4b4)Tb4b4b4:
T8b949e"""
Encrypts information for the identity.

:param plaintext: The plaintext to be encrypted as *bytes*.
:returns: Ciphertext token as *bytes*.
:raises: *KeyError* if the instance does not hold a public key.
"""
Tff7b72if Tff7b72selfTff7b72.Td2a8ffpub Tff7b72!= Tff7b72NoneTb4b4b4:
Te6edf3ephemeral_key Tff7b72= Te6edf3X25519PrivateKeyTff7b72.Td2a8ffgenerateTb4b4b4(Tb4b4b4)
Te6edf3ephemeral_pub_bytes Tff7b72= Te6edf3ephemeral_keyTff7b72.Td2a8ffpublic_keyTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ffpublic_bytesTb4b4b4(Tb4b4b4)

Tff7b72if Te6edf3ratchet Tff7b72!= Tff7b72NoneTb4b4b4:
Te6edf3target_public_key Tff7b72= Te6edf3X25519PublicKeyTff7b72.Td2a8fffrom_public_bytesTb4b4b4(Te6edf3ratchetTb4b4b4)
Tff7b72elseTb4b4b4:
Te6edf3target_public_key Tff7b72= Tff7b72selfTff7b72.Td2a8ffpub

Te6edf3shared_key Tff7b72= Te6edf3ephemeral_keyTff7b72.Td2a8ffexchangeTb4b4b4(Te6edf3target_public_keyTb4b4b4)
Te6edf3derived_key Tff7b72= Te6edf3RNSTff7b72.Td2a8ffCryptographyTff7b72.Td2a8ffhkdfTb4b4b4(
Te6edf3lengthTff7b72=Te6edf3IdentityTff7b72.Td2a8ffDERIVED_KEY_LENGTHTb4b4b4,
Te6edf3derive_fromTff7b72=Te6edf3shared_keyTb4b4b4,
Te6edf3saltTff7b72=Tff7b72selfTff7b72.Td2a8ffget_saltTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3contextTff7b72=Tff7b72selfTff7b72.Td2a8ffget_contextTb4b4b4(Tb4b4b4)Tb4b4b4,
Tb4b4b4)

Te6edf3token Tff7b72= Te6edf3TokenTb4b4b4(Te6edf3derived_keyTb4b4b4)
Te6edf3ciphertext Tff7b72= Te6edf3tokenTff7b72.Td2a8ffencryptTb4b4b4(Te6edf3plaintextTb4b4b4)
Te6edf3token Tff7b72= Te6edf3ephemeral_pub_bytesTff7b72+Te6edf3ciphertext

Tff7b72return Te6edf3token
Tff7b72elseTb4b4b4:
Tff7b72raise Tf85149KeyErrorTb4b4b4(Ta5d6ff"Ta5d6ffEncryption failed because identity does not hold a public keyTa5d6ff"Tb4b4b4)

Tff7b72def Td2a8ff__decryptTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3shared_keyTb4b4b4, Te6edf3ciphertextTb4b4b4)Tb4b4b4:
Te6edf3derived_key Tff7b72= Te6edf3RNSTff7b72.Td2a8ffCryptographyTff7b72.Td2a8ffhkdfTb4b4b4(
Te6edf3lengthTff7b72=Te6edf3IdentityTff7b72.Td2a8ffDERIVED_KEY_LENGTHTb4b4b4,
Te6edf3derive_fromTff7b72=Te6edf3shared_keyTb4b4b4,
Te6edf3saltTff7b72=Tff7b72selfTff7b72.Td2a8ffget_saltTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3contextTff7b72=Tff7b72selfTff7b72.Td2a8ffget_contextTb4b4b4(Tb4b4b4)Tb4b4b4)

Te6edf3token Tff7b72= Te6edf3TokenTb4b4b4(Te6edf3derived_keyTb4b4b4)
Te6edf3plaintext Tff7b72= Te6edf3tokenTff7b72.Td2a8ffdecryptTb4b4b4(Te6edf3ciphertextTb4b4b4)
Tff7b72return Te6edf3plaintext

Tff7b72def Td2a8ffdecryptTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3ciphertext_tokenTb4b4b4, Te6edf3ratchetsTff7b72=Tff7b72NoneTb4b4b4, Te6edf3enforce_ratchetsTff7b72=Tff7b72FalseTb4b4b4, Te6edf3ratchet_id_receiverTff7b72=Tff7b72NoneTb4b4b4)Tb4b4b4:
T8b949e"""
Decrypts information for the identity.

:param ciphertext: The ciphertext to be decrypted as *bytes*.
:returns: Plaintext as *bytes*, or *None* if decryption fails.
:raises: *KeyError* if the instance does not hold a private key.
"""

Tff7b72if Tff7b72selfTff7b72.Td2a8ffprv Tff7b72!= Tff7b72NoneTb4b4b4:
Tff7b72if Tffa657lenTb4b4b4(Te6edf3ciphertext_tokenTb4b4b4) Tff7b72> Te6edf3IdentityTff7b72.Td2a8ffKEYSIZETff7b72/Tff7b72/T79c0ff8Tff7b72/Tff7b72/T79c0ff2Tb4b4b4:
Te6edf3plaintext Tff7b72= Tff7b72None
Tff7b72tryTb4b4b4:
Te6edf3peer_pub_bytes Tff7b72= Te6edf3ciphertext_tokenTb4b4b4[Tb4b4b4:Te6edf3IdentityTff7b72.Td2a8ffKEYSIZETff7b72/Tff7b72/T79c0ff8Tff7b72/Tff7b72/T79c0ff2Tb4b4b4]
Te6edf3peer_pub Tff7b72= Te6edf3X25519PublicKeyTff7b72.Td2a8fffrom_public_bytesTb4b4b4(Te6edf3peer_pub_bytesTb4b4b4)
Te6edf3ciphertext Tff7b72= Te6edf3ciphertext_tokenTb4b4b4[Te6edf3IdentityTff7b72.Td2a8ffKEYSIZETff7b72/Tff7b72/T79c0ff8Tff7b72/Tff7b72/T79c0ff2Tb4b4b4:Tb4b4b4]

Tff7b72if Te6edf3ratchetsTb4b4b4:
Tff7b72for Te6edf3ratchet Tff7b72in Te6edf3ratchetsTb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3ratchet_prv Tff7b72= Te6edf3X25519PrivateKeyTff7b72.Td2a8fffrom_private_bytesTb4b4b4(Te6edf3ratchetTb4b4b4)
Te6edf3ratchet_id Tff7b72= Te6edf3IdentityTff7b72.Td2a8ff_get_ratchet_idTb4b4b4(Te6edf3ratchet_prvTff7b72.Td2a8ffpublic_keyTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ffpublic_bytesTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3shared_key Tff7b72= Te6edf3ratchet_prvTff7b72.Td2a8ffexchangeTb4b4b4(Te6edf3peer_pubTb4b4b4)
Te6edf3plaintext Tff7b72= Tff7b72selfTff7b72.Td2a8ff__decryptTb4b4b4(Te6edf3shared_keyTb4b4b4, Te6edf3ciphertextTb4b4b4)
Tff7b72if Te6edf3ratchet_id_receiverTb4b4b4:
Te6edf3ratchet_id_receiverTff7b72.Td2a8fflatest_ratchet_id Tff7b72= Te6edf3ratchet_id
Tff7b72break
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Tff7b72pass

Tff7b72if Te6edf3enforce_ratchets Tff7b72and Te6edf3plaintext Tff7b72== Tff7b72NoneTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffDecryption with ratchet enforcement by Ta5d6ff"Tff7b72+Te6edf3RNSTff7b72.Td2a8ffprettyhexrepTb4b4b4(Tff7b72selfTff7b72.Td2a8ffhashTb4b4b4)Tff7b72+Ta5d6ff"Ta5d6ff failed. Dropping packet.Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4) Tff7b72if Te6edf3RNSTff7b72.Td2a8ffslTb4b4b4(Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4) Tff7b72else Tff7b72None
Tff7b72if Te6edf3ratchet_id_receiverTb4b4b4:
Te6edf3ratchet_id_receiverTff7b72.Td2a8fflatest_ratchet_id Tff7b72= Tff7b72None
Tff7b72return Tff7b72None

Tff7b72if Te6edf3plaintext Tff7b72== Tff7b72NoneTb4b4b4:
Te6edf3shared_key Tff7b72= Tff7b72selfTff7b72.Td2a8ffprvTff7b72.Td2a8ffexchangeTb4b4b4(Te6edf3peer_pubTb4b4b4)
Te6edf3plaintext Tff7b72= Tff7b72selfTff7b72.Td2a8ff__decryptTb4b4b4(Te6edf3shared_keyTb4b4b4, Te6edf3ciphertextTb4b4b4)

Tff7b72if Te6edf3ratchet_id_receiverTb4b4b4:
Te6edf3ratchet_id_receiverTff7b72.Td2a8fflatest_ratchet_id Tff7b72= Tff7b72None

Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffDecryption by Ta5d6ff"Tff7b72+Te6edf3RNSTff7b72.Td2a8ffprettyhexrepTb4b4b4(Tff7b72selfTff7b72.Td2a8ffhashTb4b4b4)Tff7b72+Ta5d6ff"Ta5d6ff failed: Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4) Tff7b72if Te6edf3RNSTff7b72.Td2a8ffslTb4b4b4(Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4) Tff7b72else Tff7b72None
Tff7b72if Te6edf3ratchet_id_receiverTb4b4b4:
Te6edf3ratchet_id_receiverTff7b72.Td2a8fflatest_ratchet_id Tff7b72= Tff7b72None
Tff7b72return Te6edf3plaintext
Tff7b72elseTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffDecryption failed because the token size was invalid.Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4) Tff7b72if Te6edf3RNSTff7b72.Td2a8ffslTb4b4b4(Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4) Tff7b72else Tff7b72None
Tff7b72return Tff7b72None
Tff7b72elseTb4b4b4:
Tff7b72raise Tf85149KeyErrorTb4b4b4(Ta5d6ff"Ta5d6ffDecryption failed because identity does not hold a private keyTa5d6ff"Tb4b4b4)


Tff7b72def Td2a8ffsignTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3messageTb4b4b4)Tb4b4b4:
T8b949e"""
Signs information by the identity.

:param message: The message to be signed as *bytes*.
:returns: Signature as *bytes*.
:raises: *KeyError* if the instance does not hold a private key.
"""
Tff7b72if Tff7b72selfTff7b72.Td2a8ffsig_prv Tff7b72!= Tff7b72NoneTb4b4b4:
Tff7b72tryTb4b4b4:
Tff7b72return Tff7b72selfTff7b72.Td2a8ffsig_prvTff7b72.Td2a8ffsignTb4b4b4(Te6edf3messageTb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffThe identity Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Tff7b72selfTb4b4b4)Tff7b72+Ta5d6ff"Ta5d6ff could not sign the requested message. The contained exception was: Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_ERRORTb4b4b4)
Tff7b72raise Te6edf3e
Tff7b72elseTb4b4b4:
Tff7b72raise Tf85149KeyErrorTb4b4b4(Ta5d6ff"Ta5d6ffSigning failed because identity does not hold a private keyTa5d6ff"Tb4b4b4)

Tff7b72def Td2a8ffvalidateTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3signatureTb4b4b4, Te6edf3messageTb4b4b4)Tb4b4b4:
T8b949e"""
Validates the signature of a signed message.

:param signature: The signature to be validated as *bytes*.
:param message: The message to be validated as *bytes*.
:returns: True if the signature is valid, otherwise False.
:raises: *KeyError* if the instance does not hold a public key.
"""
Tff7b72if Tff7b72selfTff7b72.Td2a8ffpub Tff7b72!= Tff7b72NoneTb4b4b4:
Tff7b72tryTb4b4b4:
Tff7b72selfTff7b72.Td2a8ffsig_pubTff7b72.Td2a8ffverifyTb4b4b4(Te6edf3signatureTb4b4b4, Te6edf3messageTb4b4b4)
Tff7b72return Tff7b72True
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Tff7b72return Tff7b72False
Tff7b72elseTb4b4b4:
Tff7b72raise Tf85149KeyErrorTb4b4b4(Ta5d6ff"Ta5d6ffSignature validation failed because identity does not hold a public keyTa5d6ff"Tb4b4b4)

Tff7b72def Td2a8ffproveTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3packetTb4b4b4, Te6edf3destinationTff7b72=Tff7b72NoneTb4b4b4)Tb4b4b4:
Te6edf3signature Tff7b72= Tff7b72selfTff7b72.Td2a8ffsignTb4b4b4(Te6edf3packetTff7b72.Td2a8ffpacket_hashTb4b4b4)
Tff7b72if Te6edf3RNSTff7b72.Td2a8ffReticulumTff7b72.Td2a8ffshould_use_implicit_proofTb4b4b4(Tb4b4b4)Tb4b4b4:
Te6edf3proof_data Tff7b72= Te6edf3signature
Tff7b72elseTb4b4b4:
Te6edf3proof_data Tff7b72= Te6edf3packetTff7b72.Td2a8ffpacket_hash Tff7b72+ Te6edf3signature
Tff7b72if Te6edf3destination Tff7b72== Tff7b72NoneTb4b4b4:
Te6edf3destination Tff7b72= Te6edf3packetTff7b72.Td2a8ffgenerate_proof_destinationTb4b4b4(Tb4b4b4)

Te6edf3proof Tff7b72= Te6edf3RNSTff7b72.Td2a8ffPacketTb4b4b4(Te6edf3destinationTb4b4b4, Te6edf3proof_dataTb4b4b4, Te6edf3RNSTff7b72.Td2a8ffPacketTff7b72.Td2a8ffPROOFTb4b4b4, Te6edf3attached_interface Tff7b72= Te6edf3packetTff7b72.Td2a8ffreceiving_interfaceTb4b4b4)
Te6edf3proofTff7b72.Td2a8ffsendTb4b4b4(Tb4b4b4)

Tff7b72def Tff7b72__str__Tb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3RNSTff7b72.Td2a8ffprettyhexrepTb4b4b4(Tff7b72selfTff7b72.Td2a8ffhashTb4b4b4)


──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────